<template>
  <div class="right-all full-height relative-position">
    <!--  头部-->
    <div class="file-head row no-wrap bg-primary text-white form-inline">
      <q-btn-dropdown
        label="上传"
        unelevated
        color="white"
        text-color="primary"
        v-has="{ id: Enums.SYS_PERMISSION.G_UPLOAD_BTN.value }"
        class="margin-r-10 btn-dropdown"
      >
        <q-list dense>
          <q-item clickable v-close-popup class="no-padding">
            <q-item-section>
              <q-btn
                label="上传文件"
                unelevated
                color="white"
                text-color="primary"
                @click.stop="$refs.uploadInput.click()"
                class="margin-r-10"
              >
                <input
                  v-show="false"
                  ref="uploadInput"
                  type="file"
                  @change="uploadFile($event)"
                  multiple
                  class="q-uploader__input overflow-hidden absolute-full"
                />
              </q-btn>
            </q-item-section>
          </q-item>
          <q-item clickable v-close-popup class="no-padding">
            <q-item-section>
              <q-btn
                label="上传文件夹"
                unelevated
                color="white"
                text-color="primary"
                @click.stop="$refs.uploadInputAll.click()"
                class="margin-r-10"
              >
                <input
                  v-show="false"
                  ref="uploadInputAll"
                  type="file"
                  @change="uploadFile($event)"
                  webkitdirectory
                  class="q-uploader__input overflow-hidden absolute-full"
                />
              </q-btn>
            </q-item-section>
          </q-item>
        </q-list>
      </q-btn-dropdown>
      <q-btn
        label="下载文件"
        :disable="actFile.length === 0"
        @click="onDownload"
        unelevated
        v-has="{ id: Enums.SYS_PERMISSION.G_DOWN_BTN.value }"
        color="white"
        text-color="primary"
        class="margin-r-10"
      >
        <!-- <input ref="uploadInput" webkitdirectory multiple
             v-show="actFile.length>0"
             class="q-uploader__input overflow-hidden absolute-full opacity-0" /> -->
      </q-btn>
      <q-btn
        @click="showCompare"
        label="文件对比"
        unelevated
        color="white"
        text-color="primary"
        class="margin-r-10"
      />
      <q-btn
        @click="deleteAll"
        label="批量删除"
        unelevated
        color="white"
        text-color="primary"
        v-has="{ id: Enums.SYS_PERMISSION.G_DELETE_BTN.value }"
        class="margin-r-10"
        :disable="actFile.length === 0"
      />
      <q-btn
        @click="onAudit"
        label="标记设置"
        unelevated
        color="white"
        text-color="primary"
        v-has="{ id: Enums.SYS_PERMISSION.G_PAIR_BTN.value }"
      />
      <q-space></q-space>
      <q-input
        outlined
        dense
        ref="selectInput"
        @input="changeFileSearch"
        v-model.trim="searchFile"
        clearable
        @clear="clearSearchVal()"
        clear-icon="close"
        class="quik-search"
        bg-color="white"
      >
        <template v-slot:prepend>
          <q-icon
            name="iconfont icontubiao-21"
            style="color: #999;font-size: 18px"
            @click="onFindFile"
          />
        </template>
      </q-input>
      <q-icon name="iconfont icontubiao-58" class="icon" @click="back()">
        <q-tooltip>返回上一级</q-tooltip>
      </q-icon>
      <q-icon
        v-if="!isSearch"
        :name="
          lookStatus === 'list'
            ? 'iconfont icontubiao-104'
            : 'iconfont icontubiao-57'
        "
        class="icon"
        @click="changeLookStatus"
      >
        <q-tooltip>切换显示模式</q-tooltip>
      </q-icon>
      <q-icon name="iconfont icontubiao-34" class="icon" @click="refreshFun">
        <q-tooltip>刷新</q-tooltip>
      </q-icon>
    </div>
    <!--  路径-->
    <position
      :position="curDir.name"
      :total="total"
      @goto="goto"
      :isSearch="isSearch"
    ></position>
    <!--  内容-->
    <div v-if="isSearch" class="list-content relative-position" ref="fileList">
      <div class="full-height" @click.self="clearActFile">
        <q-table
          class="table-file"
          :pagination="pagination"
          no-data-label="暂无数据"
          :data="files"
          :columns="columns"
          row-key="id"
          hide-bottom
          binary-state-sort
          @request="onRequest"
        >
          <template v-slot:body="props">
            <file-item-tr
              :file="props"
              :is-active="isActDay(props.row)"
              :ref="'fileItemTr' + props.row.id"
              @selFiles="selFiles"
              @dblclickE="dblclickE"
              @setFile="setFile"
              @setNewNameFun="setNewNameFun"
              @deleteFun="deleteFun"
              :isShowDui="isShowDui"
              :isSearch="isSearch"
              :isTranFlag="isTranFlag"
              @signFile="onSignFile"
              @goToFile="goToFile"
              @addCompareList="addCompareList"
              @setDragItem="setDragItem"
              @editFile="editFile"
              @showVersionList="showVersionList"
            />
          </template>
        </q-table>
        <q-menu touch-position context-menu>
          <q-list dense style="min-width: 150px">
            <q-item clickable v-close-popup @click="newFolder"
                    v-has="{ id: Enums.SYS_PERMISSION.G_ADD_BTN.value }">
              <q-item-section>新建文件夹</q-item-section>
            </q-item>
            <q-item clickable v-close-popup @click="newFile"
                    v-has="{ id: Enums.SYS_PERMISSION.G_ADD_BTN.value }">
              <q-item-section>新建文件</q-item-section>
            </q-item>
          </q-list>
        </q-menu>
      </div>
      <div class="box-select" ref="boxSelect"></div>
      <q-inner-loading :showing="loading">
        <q-spinner-gears size="50px" color="primary" />
      </q-inner-loading>
    </div>
    <div
      v-else
      class="list-content drop-target relative-position"
      @mousedown="boxStart($event, 'fileList')"
      ref="fileList"
    >
      <div
        class="full-height"
        v-if="lookStatus === 'bigIcon'"
        @click.self="clearActFile()"
      >
        <q-scroll-area
          :thumb-style="CommonConfig.thumbStyle"
          class="full-height"
        >
          <div class="full-height list">
            <file-item
              v-for="(file, fileIndex) in files"
              :key="fileIndex"
              :ref="'fileItem' + file.id"
              :file="file"
              :file-index="fileIndex"
              :is-active="isActDay(file)"
              @selFiles="selFiles"
              @dblclickE="dblclickE"
              @setFile="setFile"
              @setNewNameFun="setNewNameFun"
              @deleteFun="deleteFun"
              :isShowDui="isShowDui"
              :isTranFlag="isTranFlag"
              @signFile="onSignFile"
              :isSupportDownload="true"
              @addCompareList="addCompareList"
              @setDragItem="setDragItem"
              @editFile="editFile"
              @showVersionList="showVersionList"
            />
          </div>
        </q-scroll-area>
        <q-menu touch-position context-menu>
          <q-list dense style="min-width: 150px">
            <q-item clickable v-close-popup @click="newFolder" v-has="{ id: Enums.SYS_PERMISSION.G_ADD_BTN.value }">
              <q-item-section>新建文件夹</q-item-section>
            </q-item>
            <q-item clickable v-close-popup @click="newFile" v-has="{ id: Enums.SYS_PERMISSION.G_ADD_BTN.value }">
              <q-item-section>新建文件</q-item-section>
            </q-item>
          </q-list>
        </q-menu>
      </div>
      <div class="full-height" v-else @click.self="clearActFile">
        <q-table
          class="table-file"
          :pagination="pagination"
          no-data-label="暂无数据"
          :data="files"
          :columns="columns"
          row-key="id"
          hide-bottom
          binary-state-sort
          @request="onRequest"
        >
          <template v-slot:body="props">
            <file-item-tr
              :file="props"
              :is-active="isActDay(props.row)"
              :ref="'fileItemTr' + props.row.id"
              @selFiles="selFiles"
              @dblclickE="dblclickE"
              @setFile="setFile"
              @setNewNameFun="setNewNameFun"
              @deleteFun="deleteFun"
              :isShowDui="isShowDui"
              :isTranFlag="isTranFlag"
              @signFile="onSignFile"
              @addCompareList="addCompareList"
              @setDragItem="setDragItem"
              @editFile="editFile"
              @showVersionList="showVersionList"
            />
          </template>
        </q-table>
        <q-menu touch-position context-menu>
          <q-list dense style="min-width: 150px">
            <q-item clickable v-close-popup @click="newFolder" v-has="{ id: Enums.SYS_PERMISSION.G_ADD_BTN.value }">
              <q-item-section>新建文件夹</q-item-section>
            </q-item>
            <q-item clickable v-close-popup @click="newFile" v-has="{ id: Enums.SYS_PERMISSION.G_ADD_BTN.value }">
              <q-item-section>新建文件</q-item-section>
            </q-item>
          </q-list>
        </q-menu>
      </div>
      <div class="box-select" ref="boxSelect"></div>
      <q-inner-loading :showing="loading">
        <q-spinner-gears size="50px" color="primary" />
      </q-inner-loading>
    </div>
    <!--        底部-->
    <div class="file-bottom">
      <div
        class="progressResult text-primary text-underline cursor-pointer"
        @click="showProgressResult"
      >
<!--        传输记录：正在传输({{ progressFiles.length }})； 传输成功({{-->
<!--          successProgressFiles.length-->
<!--        }})； 传输失败({{ failProgressFiles.length }})-->
      </div>
    </div>
    <!--  文件内容编辑-->
    <code-edit
      ref="codeEdit"
      :value="editFileContent"
      :name="editFileName"
      :decode="edtiFileDecode"
      :path="editFilePath"
      :state="codeState"
      @refreshList="refreshFun"
      @save="saveFile"
    />
    <!--  文件对比列表-->
    <compare-file
      ref="CompareFile"
      :client="client"
      :requestId="requestId"
      :drag-item="dragItem"
      :stat-pos="statPos"
      @compare="compareDetail"
    />
    <!--  版本履历-->
    <version-list ref="versionList"></version-list>
    <!--  右下角正在上传的弹框-->
    <progress-dialog ref="progressDialog" :list="progressFiles" />
    <!--  文件传输记录-->
    <progress-result-dialog
      ref="progressResult"
      :doing-data="doingProgressFiles"
      :success-data="successProgressFiles"
      :fail-data="failProgressFiles"
      @delOneRecord="delOneRecord"
      @clearRecord="clearRecord"
    />
    <!--  文件内容对比查看-->
    <code-merge ref="codeMerge"></code-merge>
    <!--  选择人审核-->
    <audit-dialog ref="AUDITDIALOG" :toolType="1" @refreshFun="refreshFun" />
  </div>
</template>

<script>
import Position from './position'
import FileItem from './file-item'
import FileItemTr from './file-item-tr'
import CodeEdit from 'src/components/code-edit/index'
import CompareFile from './compare-file1'
import VersionList from './version-list'
import ProgressDialog from './progress-dialog'
import ProgressResultDialog from './progress-result-dialog'
import CodeMerge from 'src/components/code-merge'
import {
  getOffsetLeft,
  getOffsetTop,
  getFiletype,
  isUploadFile
} from 'src/assets/js/util'
import {
  loadProgressSuccessRecord,
  loadProgressFailRecord,
  saveProgressSuccessRecord,
  saveProgressFailRecord,
  clearProgressSuccessRecord,
  clearProgressFailRecord
} from 'src/assets/js/storage'
import {
  newDir,
  newFile,
  editFile,
  setNewName,
  rmDir,
  getUploadRecord,
  getBasisUrl,
  cloudFileExist
} from 'src/boot/program-v2/cloud'
import {
  getCloudList,
  rmFileToRecyclebin,
  getChildPath,
  setFileToZip,
  rmFileAll,
  findFile
} from 'src/boot/program-v2/G-gov'
import { fileExist, writeFile } from 'src/assets/js/file-dir'
import { mapGetters } from 'vuex'
import { date } from 'quasar'
import fileMqttMixin from 'src/assets/js/webSocket'
import fileMinxins from './file-minxins'
import AuditDialog from './audit-dialog'
import SIGNMIXIN from '../sign-mixin'
import exportJs from 'src/pages/statistics/components/export'
import _ from 'lodash'
export default {
  name: 'right-all',
  mixins: [fileMqttMixin, fileMinxins, SIGNMIXIN],
  data () {
    return {
      lookStatus: 'bigIcon', // 查看状态, list or bigIcon
      // 路径
      position: '全部文件', // 当前位置
      // 当前选中的文件夹
      curDir: {
        size: null,
        label: '',
        name: '',
        path: '',
        source: 'cloud'
      },
      total: 0, // 一共加载的数量
      localFilePathWeb: '本地默认路径',
      // 列表位置
      loading: false, // 是否是加载状态
      actFile: [], // 选中的文件
      clickTime: null, // 区分单击与双击
      files: [],
      emptyMenu: false, // 控制空白处右键显示的菜单
      // 编辑内容
      editFileContent: '', // 要编辑文件的内容
      editFileName: '', // 要编辑文件的名字
      edtiFileDecode: '', // 要编辑文件的编码
      editFilePath: '', // 要编辑文件的路径
      codeState: 'edit', // 添加编辑状态，edit or add
      pagination: {
        sortBy: 'timestamp',
        descending: true,
        page: 1,
        rowsPerPage: 0,
        rowsNumber: 10
      },
      // 框选数据
      parentW: 0, // 外框的宽
      parentH: 0, // 外框的高
      parentX: 0, // 外框的横坐标
      parentY: 0, // 外框的中坐标
      statPos: 'localCloud', // 定义埋点位置
      dragItem: [], // 存储拖动的数据
      // 传输数据
      progressFiles: [], // 正在传输的文件
      doingProgressFiles: [], // 传输成功的列表
      successProgressFiles: [], // 传输成功的列表
      failProgressFiles: [], // 传输失败的列表
      progressTime: null, // 存储定时器
      clientCloud: null, // oss上传下载用
      searchFile: '',
      isSearch: false,
      // 文件对比
      compareList: [] // 文件对比数据
    }
  },
  computed: {
    ...mapGetters(['userInfo', 'client']),
    // 表格配置
    columns () {
      return [
        // 列表的头部
        {
          name: 'label',
          align: 'left',
          label: '文件名',
          field: 'label',
          style: 'width: 60%'
        },
        { name: 'size', align: 'left', label: '大小', field: 'size' },
        !this.isSearch
          ? {
            name: 'timestamp',
            label: '修改时间',
            field: 'timestamp',
            sortable: true
          }
          : { name: 'timestamp', label: '所在目录', field: 'timestamp' }
      ]
    }
  },
  created () {
    this.successProgressFiles = this.sortRecord(
      loadProgressSuccessRecord(this.userInfo.tenant_id)
    )
    this.failProgressFiles = this.sortRecord(
      loadProgressFailRecord(this.userInfo.tenant_id)
    )
    this.getInfo()
  },
  methods: {
    changeFileSearch (val) {
      console.log(val)
    },
    onFindFile () {
      this.isSearch = true
      _.debounce(this.findFile(), 200)
    },
    // 清除搜索值
    clearSearchVal () {
      this.searchFile = ''
    },
    async findFile () {
      this.loading = true
      this.files = []
      this.total = 0
      const res = await findFile(this.searchFile)
      let dirs = this.initInfo(res.data.filter(v => !v.file), false)
      let files = this.initInfo(
        res.data.filter(v => v.file),
        true,
        res.data.filter(v => v.file).length
      )
      this.files = [].concat(dirs, files)
      this.total = res.data.length
      console.log(this.total)
      this.loading = false
      this.curDir = {
        size: null,
        label: '',
        name: '',
        path: '',
        source: 'cloud'
      }
    },
    goToFile (file) {
      this.isSearch = false
      this.searchFile = ''
      Object.assign(this.curDir, _.pick(file, Object.keys(this.curDir)))
      let pathArr = this.curDir.path.split('/')
      pathArr = pathArr.slice(0, pathArr.length - 1)
      let path = pathArr.length === 1 ? '' : pathArr.join('/') + '/'
      this.getInfo(path)
    },
    onAudit () {
      this.$refs.AUDITDIALOG.showDialog()
    },
    deleteAll () {
      let params = {
        list: this.actFile.map(v => {
          return _.pick(v, ['isFile', 'path', 'size'])
        })
      }
      this.$utils.showMessage(
        'icontubiao-28',
        '是否确认全部删除?',
        () => {
          rmFileAll(params).then(res => {
            this.$message.success('操作成功')
            this.refreshFun()
          })
        },
        true
      )
    },
    // 切换显示状态
    changeLookStatus () {
      this.lookStatus = this.lookStatus === 'list' ? 'bigIcon' : 'list'
      this.pagination.sortBy = 'timestamp'
      this.pagination.descending = true
      this.refreshFun()
    },
    // 刷新
    refreshFun () {
      this.isSearch = false
      this.searchFile = ''
      this.getInfo(this.curDir.path)
    },
    // 返回上一级
    back () {
      let pathArr = this.curDir.path.split('/')
      pathArr.pop()
      pathArr.pop()
      let path
      if (pathArr.length > 1) {
        path = pathArr.join('/') + '/'
      } else {
        path = ''
      }
      this.getInfo(path)
    },
    goto (pathIndex) {
      let pathArr = this.curDir.path.split('/')
      pathArr = pathArr.slice(0, pathIndex + 1)
      console.log(pathArr)
      let path = pathIndex === 0 ? '' : pathArr.join('/') + '/'
      this.getInfo(path)
    },
    /**
     * 获取数据
     * @param path 路径
     */
    getInfo (path = '') {
      this.loading = true
      getCloudList(path)
        .then(res => {
          let dirs = this.initInfo(res.data.dirs, false)
          let files = this.initInfo(res.data.files, true, res.data.dirs.length)
          this.files =
            this.lookStatus === 'bigIcon' ||
            (this.lookStatus === 'list' &&
              this.pagination.sortBy &&
              this.pagination.descending)
              ? [].concat(dirs, files)
              : [].concat(files, dirs)
          this.total = this.files.length
          this.curDir = {
            ...res.data.curDir,
            source: 'cloud'
          }
        })
        .finally(() => {
          this.loading = false
        })
    },
    /**
     * 给数据添加必要的属性
     * @param info
     * @param isFile 是否是文件
     * @returns 新数据
     */
    initInfo (info, isFile, dirLength = 0) {
      let data = info.map((item, index) => {
        let type = isFile ? getFiletype(item.label) : 'other'
        let id = isFile ? index + 1 + dirLength : index + 1
        return {
          ...item,
          id,
          _name: item.label,
          isFile: isFile,
          type,
          source: 'cloud',
          icon: isFile
            ? 'img:statics/svg/' + type + '.svg'
            : 'img:statics/svg/file-icon.svg',
          children: []
        }
      })
      if (this.lookStatus === 'list' && this.pagination.sortBy) {
        let sortBy = this.pagination.sortBy
        let descending = this.pagination.descending
        const sortFn = descending
          ? (a, b) =>
            a[sortBy] > b[sortBy] ? -1 : a[sortBy] < b[sortBy] ? 1 : 0
          : (a, b) =>
            a[sortBy] > b[sortBy] ? 1 : a[sortBy] < b[sortBy] ? -1 : 0
        data = data.sort(sortFn)
      }
      return data
    },
    // 排序
    onRequest (props) {
      const { sortBy, descending } = props.pagination
      if (sortBy) {
        const sortFn = descending
          ? (a, b) =>
            a[sortBy] > b[sortBy] ? -1 : a[sortBy] < b[sortBy] ? 1 : 0
          : (a, b) =>
            a[sortBy] > b[sortBy] ? 1 : a[sortBy] < b[sortBy] ? -1 : 0
        let dirs = this.files.filter(item => !item.isFile).sort(sortFn)
        let files = this.files.filter(item => item.isFile).sort(sortFn)
        this.files = descending
          ? [].concat(dirs, files)
          : [].concat(files, dirs)
        this.pagination.sortBy = sortBy
        this.pagination.descending = descending
      }
    },
    // 单击选中文件，按住shift、ctrl多选
    selFiles (e, item) {
      clearTimeout(this.clickTime)
      this.clickTime = setTimeout(() => {
        if (e.ctrlKey) {
          // 按住ctrl键
          const index = this.actFile.findIndex(file => {
            return file.id === item.id
          })
          if (index > -1) {
            this.actFile = this.actFile.filter(file => {
              return file.id !== item.id
            })
          } else {
            this.actFile.push(item)
          }
        } else if (e.shiftKey) {
          // 按住shift键
          if (this.actFile.length === 0) {
            this.actFile.push(item)
          } else {
            const maxIndex = this.getMaxIndex()
            const index = this.files.findIndex(file => {
              return file.id === item.id
            })
            let actFile = this.files.filter((file, fileIndex) => {
              const condition =
                (index > maxIndex &&
                  fileIndex <= index &&
                  fileIndex >= maxIndex) ||
                (index < maxIndex &&
                  fileIndex >= index &&
                  fileIndex <= maxIndex) ||
                (index === maxIndex && fileIndex === index)
              return condition
            })
            this.actFile = actFile
          }
        } else {
          // 单选
          const index = this.actFile.findIndex(file => {
            return file.id === item.id
          })
          this.actFile = index > -1 ? [] : [item]
        }
      }, 250)
    },
    // 获取存储在选中的file里面的最大最小角标
    getMaxIndex () {
      const indexArr = []
      this.actFile.forEach(item => {
        const index = this.files.findIndex(file => {
          return file.id === item.id
        })
        if (index > -1) {
          indexArr.push(index)
        }
      })
      indexArr.sort((a, b) => (a > b ? 1 : -1))
      return indexArr[indexArr.length - 1]
    },
    // 选中一个文件
    setFile (item) {
      this.actFile = [item]
    },
    // 双击进入子级文件夹
    dblclickE (file) {
      clearTimeout(this.clickTime)
      if (!file.isFile) {
        this.actFile = []
        this.curDir = file
        this.getInfo(file.path)
      } else {
        console.log('双击查看')
      }
    },
    // 清空选中文件列表
    clearActFile (event) {
      // if (event.target.className === '')
      this.actFile = []
    },
    // 是否是选中状态
    isActDay (file) {
      const index = this.actFile.findIndex(item => {
        return item.id === file.id
      })
      return index > -1
    },
    // 重命名文件夹、文件
    setNewNameFun (item, rename) {
      console.log(this.files, rename)
      let ref =
        (this.lookStatus === 'bigIcon' ? 'fileItem' : 'fileItemTr') + item.id
      if (
        this.files
          .filter(v => v.isFile)
          .map(y => y.label)
          .includes(rename)
      ) {
        this.$refs[ref][0].edit = false
        this.$refs[ref].rename = item.label
        this.noticeMessage('名称已经存在,请重新命名!')
        return
      }
      let path = item.isFile
        ? item.path
        : item.path.slice(0, item.path.length - 1)
      let oldKey = item.isFile ? path : path + '/'
      const params = {
        newKey: rename,
        oldKey
      }
      setNewName(params)
        .then(res => {
          if (this.$refs[ref].edit) {
            this.$refs[ref].edit = false
          } else {
            this.$refs[ref][0].edit = false
          }
          this.refreshFun()
        })
        .finally(() => {
          if (this.$refs[ref].rename) {
            this.$refs[ref].rename = item.label
            this.$refs[ref].edit = false
          } else {
            this.$refs[ref][0].rename = item.label
            this.$refs[ref][0].edit = false
          }
        })
    },
    // 删除文件和文件夹
    deleteFun (item) {
      this.$q
        .dialog({
          title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 确定要删除${item.label}吗？</p>`,
          html: true,
          ok: {
            unelevated: true,
            label: '确认'
          },
          cancel: {
            unelevated: true,
            outline: true,
            label: '取消'
          }
        })
        .onOk(data => {
          if (item.isFile) {
            let params = {
              key: item.path,
              size: item.size
            }
            rmFileToRecyclebin(params).then(res => {
              this.refreshFun()
            })
          } else {
            let path = item.path
            rmDir(path).then(res => {
              this.refreshFun()
            })
          }
        })
    },
    // 新建文件夹
    newFolder () {
      this.$q
        .dialog({
          class: 'prompt-dialog',
          title: '文件夹名称',
          message: '支持同时创建多级文件夹，用 / 隔开',
          prompt: {
            model: '',
            isValid: val => val.length > 0 && val.length < 20,
            type: 'text'
          },
          ok: {
            unelevated: true,
            label: '确认'
          },
          cancel: {
            unelevated: true,
            outline: true,
            label: '取消'
          },
          persistent: true
        })
        .onOk(res => {
          let data = res.trim()
          if (data.length === 0) {
            this.noticeMessage('名称不能为空')
            return false
          }
          if (data.length > 20) {
            this.noticeMessage('名称长度必须小于20')
            return false
          }
          let findIndex = this.files.findIndex(
            item => !item.isFile && item.label === data
          )
          if (findIndex > -1) {
            this.noticeMessage(`文件夹${data}已存在`)
            return false
          }
          let path = this.curDir.path
          newDir(path + data + '/').then(res => {
            this.refreshFun()
          })
        })
    },
    // 新建文件
    newFile () {
      this.$q
        .dialog({
          class: 'prompt-dialog',
          title: '文件名称',
          prompt: {
            model: '',
            type: 'text'
          },
          ok: {
            unelevated: true,
            label: '确认'
          },
          cancel: {
            unelevated: true,
            outline: true,
            label: '取消'
          },
          persistent: true
        })
        .onOk(res => {
          let data = res.trim()
          if (data.length === 0) {
            this.noticeMessage('名称不能为空')
            return false
          }
          if (data.length > 20) {
            this.noticeMessage('名称长度必须小于20')
            return false
          }
          if (isUploadFile(data)) {
            this.noticeMessage('该类型文件无法新建')
            return false
          }
          let findIndex = this.files.findIndex(
            item => item.isFile && item.label === data
          )
          if (findIndex > -1) {
            this.noticeMessage(`文件${data}已存在`)
            return false
          }
          this.editFilePath = this.curDir.path + data
          this.editFileName = data
          this.editFileContent = ''
          this.edtiFileDecode = ''
          this.codeState = 'add'
          this.$refs.codeEdit.showDialog()
        })
    },
    // 显示文件对比
    showCompare () {
      this.$refs.CompareFile.show()
      this.actFile = []
    },
    // 保存文件
    saveFile (fileName, code) {
      let frontPath = this.curDir.path
      let nameArr = fileName.split('/')
      if (this.codeState === 'add') {
        const params = {
          dir: frontPath,
          fileName: nameArr[nameArr.length - 1],
          content: code
        }
        newFile(params).then(res => {
          this.successMessage(`添加文件${this.editFileName}成功`)
          this.refreshFun()
          this.$refs.codeEdit.hideDialog()
        })
      } else if (this.codeState === 'edit') {
        const params = {
          key: fileName,
          content: code
        }
        editFile(params).then(res => {
          this.successMessage(`修改文件${this.editFileName}成功`)
          this.refreshFun()
          this.$refs.codeEdit.hideDialog()
        })
      }
    },
    // 传输文件-上传文件
    // 本地上传文件到云端
    async uploadFile (event) {
      // .DS_Store
      const files = event.target.files
      // 判断是否选择了文件
      if (files.length === 0) {
        return
      }
      // 验证文件是否符合规则
      // if (!this.testCloudFiles(files)) {
      //   return false
      // }
      for (let i = 0; i < files.length; i++) {
        let file = files[i]
        if (isUploadFile(file.name)) {
          this.errMessage('部分类型文件无法上传！')
          continue
        }
        if (file.size > 50 * 1024 * 1024) {
          this.errMessage(`文件${file.name}大小超过50M，无法上传`)
          continue
        }
        // 判断文件是否存在
        let savePath =
          (this.curDir.path === ''
            ? this.userInfo.tenant_id + '/'
            : this.curDir.path) + (file.webkitRelativePath || file.name)
        // 检查文件是否存在
        cloudFileExist(savePath).then(res => {
          if (res.data) {
            this.$q
              .dialog({
                title: `<p class="dialog-notice-title">
<i class="iconfont icontubiao-28" ></i> 提示</p>`,
                message: '文件' + file.name + '已存在，是否覆盖文件?',
                html: true,
                ok: {
                  unelevated: true,
                  label: '确认'
                },
                cancel: {
                  unelevated: true,
                  outline: true,
                  label: '取消'
                },
                persistent: true
              })
              .onOk(data => {
                // 发送文件
                this.putToCloud(file, savePath)
              })
          } else {
            // 发送文件
            this.putToCloud(file, savePath)
          }
        })
      }
      event.target.value = ''
    },
    /**
     * 发送本地文件到云端的方法并监听进度
     * @param sendFile 要发送的文件
     * @param savePath 要发送到云端的位置
     * @returns {Promise<void>}
     */
    putToCloud (sendFile, savePath) {
      let self = this
      let retryCount = 0 // 上传计数
      let retryCountMax = 3 // 最多上传3次
      // let checkpoint
      let startTime = new Date() // 上传开始时间
      let acceptPath =
        (this.curDir.name === '' ? '全部文件/' : this.curDir.name) +
        (sendFile.webkitRelativePath || sendFile.name)
      if (sendFile.size === 0) {
        let progress = {
          name: sendFile.name, // 文件名字
          progress: 1, // 传输进度
          state: 'fail', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
          partSize: 100 * 1024, // 每次上传的大小
          fileSize: sendFile.size, // 文件总大小
          acceptPath, // 接收方地址
          startTime, // 开始时间
          sender: 'local', // 发送方
          acceptor: 'cloud', // 接收方
          reason: '文件内容不允许为空',
          endTime: date.formatDate(new Date(), 'MM-DD HH:mm'),
          useTime: self.getUseTime(startTime, new Date())
        }
        this.addProgressFiles(progress)
        return
      }
      let progress = {
        name: sendFile.name, // 文件名字
        progress: 0, // 传输进度
        state: 'upload', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
        partSize: 100 * 1024, // 每次上传的大小
        fileSize: sendFile.size, // 文件总大小
        acceptPath: acceptPath, // 接收方地址
        startTime, // 开始时间
        sender: 'local', // 发送方
        acceptor: 'cloud', // 接收方
        endTime: date.formatDate(new Date(), 'MM-DD HH:mm'),
        useTime: self.getUseTime(startTime, new Date())
      }
      self.addProgressFiles(progress)
      // 上传函数
      const uploadFile = function uploadFile (progress) {
        const params = {
          cloudPath: savePath,
          file: sendFile
        }
        // self.addProgressFiles(progress)
        return getUploadRecord(params)
          .then(res => {
            if (res.success) {
              // progress = {
              //   name: sendFile.name, // 文件名字
              //   progress: 0, // 传输进度
              //   state: 'upload', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
              //   partSize: 100 * 1024, // 每次上传的大小
              //   fileSize: sendFile.size, // 文件总大小
              //   acceptPath: acceptPath, // 接收方地址
              //   startTime, // 开始时间
              //   sender: 'local', // 发送方
              //   acceptor: 'cloud', // 接收方
              //   endTime: date.formatDate(new Date(), 'MM-DD HH:mm'),
              //   useTime: self.getUseTime(startTime, new Date())
              // }
              // self.addProgressFiles(progress)
              self.getRateOfProgress(progress)
            } else {
              // 上传出错，继续上传
              if (retryCount < retryCountMax) {
                retryCount++
                console.log('再次上传，retryCount : ' + retryCount)
                uploadFile(progress)
              }
            }
          })
          .catch(err => {
            self.getRateOfProgress(progress)
            console.log(err, 'errrrrrrrrr')
          })
      }
      uploadFile(progress)
    },
    /**
     * 进度0.1s
     *模拟传输进度
     */
    getRateOfProgress (progerss = {}) {
      let progress = Object.assign({}, progerss)
      let proNum = 0.1
      let state = 'upload'
      const timer = setInterval(() => {
        proNum += 0.1
        if (proNum > 1) {
          state = 'success'
        }
        this.$set(progress, 'progress', proNum)
        this.$set(progress, 'state', state)
        this.addProgressFiles(progress)
        if (proNum > 1) {
          clearInterval(timer)
          this.refreshFun()
        }
      }, 100)
    },
    // 验证上传到云端的文件是否符合规则
    testCloudFiles (files) {
      if (files.length > 50) {
        this.errMessage('不能超过50个文件')
        return false
      }
      for (let i = 0; i < files.length; i++) {
        if (files[i].size > 50 * 1024 * 1024) {
          this.errMessage(
            `文件${files[i].name}大小超过50M，请重新选择要传输的文件`
          )
          return false
        }
      }
      return true
    },

    // 传输文件-下载文件
    // 验证是否选择了文件
    onDownload (event) {
      let files = this.actFile
      console.log(this.actFile)
      if (files.length === 0) {
        // 阻止冒泡
        this.noticeMessage('请先选择要下载的文件')
        return
      } else if (files.length > 1) {
        this.noticeMessage('只能选择单个文件下载')
        return
      } else if (files.some(v => !v.isFile)) {
        this.onSetFileZip(files)
        return
      }
      this.downloadFiles()
    },
    // start 文件夹下载
    async onSetFileZip (file) {
      const member = file[0]
      const requestId = this.getRandom()
      const onMessageArrived = res => {
        let data = JSON.parse(res.body).data
        if (data.code === 200 && requestId === Number(data.requestId)) {
          exportJs.openDownloadDialog(data.data)
        } else {
          this.noticeMessage('请求超时，请重新下载')
        }
        this.onUnSubscribeNewBox(requestId)
      }
      this.getZipRes(requestId, onMessageArrived)
      try {
        const ret = await setFileToZip({
          folderPath: member.path,
          requestId
        })
        console.log(ret)
      } catch (err) {
        console.log(err)
        this.onUnSubscribeNewBox(requestId)
      }
    },
    getRandom (min = 1, max = 2147483647) {
      min = Math.ceil(min)
      max = Math.floor(max)
      return Math.floor(Math.random() * (max - min + 1)) + min
    },
    onUnSubscribeNewBox (cmd) {
      this.client.unsubscribe(
        `${
          this.CommonConfig.socketConfig.SOCKET_TOPIC.uploadFile.subscribeTopic
        }${cmd}`
      )
    },
    getZipRes (cmd, onMessageArrived) {
      this.client.subscribe(
        `${
          this.CommonConfig.socketConfig.SOCKET_TOPIC.uploadFile.subscribeTopic
        }${cmd}`,
        onMessageArrived,
        {
          id: `${
            this.CommonConfig.socketConfig.SOCKET_TOPIC.uploadFile
              .subscribeTopic
          }${cmd}`
        }
      )
    },
    // end
    // 云端下载文件到本地
    // TODO 下载start
    async downloadFiles () {
      // 当前选中的文件
      let files = this.actFile.filter(item => {
        return item.isFile
      })
      // 当前选中的文件夹
      let dirs = this.actFile.filter(item => {
        return !item.isFile
      })
      let { resultFiles } = await this.getChildByDirs(files, dirs)
      if (!this.testCloudFiles(resultFiles)) {
        return false
      }
      // 创建文件夹和文件
      // this.createDir(resultDirs, localPath)
      resultFiles.forEach(file => {
        this.putToLocal(file)
      })
    },
    // TODO 下载end
    // 获取云端子文件下的所有文件和文件夹
    async getChildByDirs (files, dirs) {
      let resultChild = []
      for (let i = 0; i < dirs.length; i++) {
        let item = dirs[i]
        let result = await getChildPath(item.path).then(res => {
          return res.data
        })
        resultChild = resultChild.concat(result)
      }
      let resultDirs = [],
        resultFiles = files
      resultChild.forEach(item => {
        if (item.name[item.name.length - 1] === '/') {
          resultDirs.push({
            ...item,
            isFile: false
          })
        } else {
          let labels = item.name.split('/')
          resultFiles.push({
            ...item,
            label: labels[labels.length - 1],
            isFile: true
          })
        }
      })
      return { resultDirs, resultFiles }
    },
    /**
     * 发送本地到云端文件的方法并监听进度
     * @param sendFile 要发送的云端文件文件
     * @param localFilePath 要发送到本地的位置
     * @returns {Promise<void>}
     */
    async putToLocal (sendFile) {
      let startTime = new Date()
      let progress = {
        name: sendFile.label, // 文件名字
        progress: 0, // 传输进度
        state: 'download', // 上传状态 upload:正在上传，download:正在下载，success：传输成功，fail：传输失败
        partSize: sendFile.size, // 每次上传的大小
        fileSize: sendFile.size, // 文件总大小
        acceptPath: this.localFilePathWeb, // 接收方地址
        startTime, // 开始时间
        sender: 'cloud', // 发送方
        acceptor: 'local', // 接收方
        endTime: date.formatDate(new Date(), 'MM-DD HH:mm'),
        useTime: this.getUseTime(startTime, new Date())
      }
      this.addProgressFiles(progress)
      // 流式下载文件
      const params = {
        cloudPath: sendFile.path
      }
      await getBasisUrl(params)
        .then(info => {
          console.log(info)
          writeFile(
            `${info.data}${encodeURIComponent(sendFile.path)}`,
            sendFile,
            info => {
              let fileRate = info.progress
              progress.size = info.size
              progress.acceptPath = this.localFilePathWeb
              progress.progress = fileRate
              progress.receiveBytes = info.receiveBytes
              progress.state = info.state
              progress.endTime = date.formatDate(new Date(), 'MM-DD HH:mm')
              progress.useTime = this.getUseTime(startTime, new Date())
              this.addProgressFiles(progress)
              // this.successProgressFiles.unshift(progress)
              // saveProgressSuccessRecord(this.userInfo.tenant_id, this.successProgressFiles)
            }
          )
        })
        .catch(() => {
          progress.size = sendFile.size
          progress.acceptPath = this.localFilePathWeb
          progress.progress = 'fail'
          progress.receiveBytes = sendFile.receiveBytes
          progress.state = sendFile.state
          progress.endTime = date.formatDate(new Date(), 'MM-DD HH:mm')
          progress.useTime = this.getUseTime(startTime, new Date())
          this.addProgressFiles(progress)
          this.noticeMessage('网络异常,请重新再试!')
          this.refreshFun()
        })
    },
    /**
     * 判断要上传的文件里的文件夹是否存在
     * @param localFilePath 要上传文件的路径
     * @returns {boolean}
     */
    dirExist (localFilePath) {
      let pathArr = localFilePath.split('/')
      let newPathArr = pathArr.slice(0, pathArr.length - 1)
      let dirPath = newPathArr.join('/') + '/'
      return fileExist(dirPath)
    },

    // 传输过程中相关
    // 添加上传中和上传完成的文件
    addProgressFiles (file) {
      // 添加传输目录
      const index = this.progressFiles.findIndex(item => {
        return item.name === file.name && item.acceptPath === file.acceptPath
      })

      // 开始传输
      if (index === -1) {
        this.progressFiles.unshift(file)
        this.$refs.progressDialog.showDialog()
      } else {
        this.progressFiles[index].progress = file.progress
        this.progressFiles[index].useTime = file.useTime
        this.progressFiles[index].state = file.state
      }
      // 传输失败
      if (file.state === 'fail') {
        this.failProgressFiles.unshift(file)
        saveProgressFailRecord(this.userInfo.tenant_id, this.failProgressFiles)
      } else if (file.state === 'success') {
        this.successProgressFiles.unshift(file)
        saveProgressSuccessRecord(
          this.userInfo.tenant_id,
          this.successProgressFiles
        )
      }
      this.doingProgressFiles = this.progressFiles.filter(item => {
        return item.state !== 'fail' && item.state !== 'success'
      })
      this.isOverProgress()
    },
    // 判断所有文件是否上传完成，完成择1.5s后消失
    isOverProgress () {
      if (this.doingProgressFiles.length === 0) {
        this.progressTime = setTimeout(() => {
          this.$refs.progressDialog.hideDialog()
          this.progressFiles = []
        }, 1500)
      } else {
        clearTimeout(this.progressTime)
      }
    },
    // 传输记录相关
    // 显示传输记录弹框
    showProgressResult () {
      this.$refs.progressResult.showDialog()
    },
    // 删除一条传输记录
    delOneRecord (state, file) {
      if (state === 'success') {
        this.successProgressFiles = this.successProgressFiles.filter(item => {
          return !(
            item.name === file.name && item.startTime === file.startTime
          )
        })
        saveProgressSuccessRecord(
          this.userInfo.tenant_id,
          this.successProgressFiles
        )
      }
      if (state === 'fail') {
        this.failProgressFiles = this.failProgressFiles.filter(item => {
          if (item.name === file.name) {
            return (
              item.startTime !== file.startTime && item.endTime !== file.endTime
            )
          } else {
            return (
              item.name !== file.name &&
              item.startTime !== file.startTime &&
              item.endTime !== file.endTime
            )
          }
        })
        saveProgressFailRecord(this.userInfo.tenant_id, this.failProgressFiles)
      }
    },
    // 清空传输记录
    clearRecord (state) {
      if (state === 'success') {
        this.successProgressFiles = []
        clearProgressSuccessRecord(
          this.userInfo.tenant_id,
          this.successProgressFiles
        )
      }
      if (state === 'fail') {
        this.failProgressFiles = []
        clearProgressFailRecord(
          this.userInfo.tenant_id,
          this.failProgressFiles
        )
      }
    },
    // 传输记录按照时间排序
    sortRecord (record) {
      let newRecord = record.sort((a, b) => {
        if (a.endTime < b.endTime) {
          return 1
        } else if (a.endTime > b.endTime) {
          return -1
        } else return 0
      })
      newRecord = newRecord.map(item => {
        return {
          ...item,
          acceptPath: item.hasOwnProperty('acceptPath')
            ? item.acceptPath.replace('//', '/')
            : '/'
        }
      })
      return newRecord
    },

    // 框选
    // 鼠标按下事件
    boxStart (event, parentDom) {
      if (
        event.target.tagName === 'IMG' ||
        event.target.tagName === 'SPAN' ||
        event.target.className.indexOf('txt-ellipsis') > -1
      ) {
        return true
      }
      // 判断鼠标是否是左键按下
      if (event.buttons !== 1 || event.which !== 1) return
      let parentNode = this.$refs[parentDom]
      this.parentX = getOffsetLeft(parentNode)
      this.parentY = getOffsetTop(parentNode)
      this.parentW = parentNode.clientWidth
      this.parentH = parentNode.clientHeight
      let self = this
      clearTimeout(this.mouseTime)
      let startTime = new Date()

      this.mouseOn = true
      this.startX = event.clientX - this.parentX
      this.startY = event.clientY - this.parentY
      let boxSelect = this.$refs.boxSelect
      boxSelect.style.display = 'block'
      boxSelect.style.left = this.startX + 'px'
      boxSelect.style.top = this.startY + 'px'
      boxSelect.style.zIndex = -1
      boxSelect.style.width = 0
      boxSelect.style.height = 0
      document.onmousemove = function (event) {
        self.boxMove(event, parentDom)
      }
      this.$refs[parentDom].onmouseup = function (event) {
        // self.$refs[parentDom].onmousemove = null
        document.onmousemove = null
        clearTimeout(this.mouseTime)
        let endTime = new Date()
        if (endTime.getTime() - startTime.getTime() < 200) {
          self.isClickEvent = true
        }
        self.boxStop(event)
      }
    },
    // 鼠标移动事件
    boxMove (event, parentDom) {
      // 如果框选没有开启。退出
      if (!this.mouseOn) return

      let clientX = event.clientX
      let clientY = event.clientY
      let _x = clientX - this.parentX
      let _y = clientY - this.parentY
      let boxSelect = this.$refs.boxSelect

      boxSelect.style.left = Math.min(_x, this.startX) + 'px'
      boxSelect.style.top = Math.min(_y, this.startY) + 'px'
      boxSelect.style.width = Math.abs(_x - this.startX) + 'px'
      boxSelect.style.height = Math.abs(_y - this.startY) + 'px'
      boxSelect.style.zIndex = 100
      this.findNodes(event)
      // 当框选超出范围时，结束框选操作,取消move和mouseup监听
      if (
        clientX < this.parentX ||
        clientX > this.parentX + this.parentW ||
        clientY < this.parentY ||
        clientY > this.parentY + this.parentH
      ) {
        document.onmousemove = null
        this.$refs[parentDom].onmouseup = null
        clearTimeout(this.mouseTime)

        this.boxStop(event)
      }
    },
    // 鼠标松开事件
    boxStop (event) {
      this.mouseOn = false
      this.findNodes(event)
      let boxSelect = this.$refs.boxSelect
      boxSelect.style.display = 'none'
      boxSelect.style.width = 0
      boxSelect.style.height = 0
    },
    // 获取框选下的元素
    findNodes (event) {
      let dayNodes = document.getElementsByClassName('file-item')
      let boxSelect = this.$refs.boxSelect
      let selectedEls = []
      // 获取框的参数
      let l = boxSelect.offsetLeft
      let t = boxSelect.offsetTop
      let w = boxSelect.offsetWidth
      let h = boxSelect.offsetHeight

      for (let i = 0; i < dayNodes.length; i++) {
        let dayNode = dayNodes[i]
        let sl = dayNode.offsetWidth + dayNode.offsetLeft
        let st = dayNode.offsetHeight + dayNode.offsetTop
        if (
          sl > l &&
          st > t &&
          dayNode.offsetLeft < l + w &&
          dayNode.offsetTop < t + h
        ) {
          selectedEls.push(this.files[i])
        }
      }
      if (event.ctrlKey || event.shiftKey) {
        this.actFile = this.actFile.concat(selectedEls)
      } else {
        this.actFile = selectedEls
      }
    },
    // 提示
    // 注意提示
    noticeMessage (message) {
      this.$message.warning(message)
    },
    // 成功提示
    successMessage (message) {
      this.$message.success(message)
    },
    // 根据开始时间和结束时间，获取累计用时时间，返回hh:mm:ss
    getUseTime (startTime, endTime) {
      let useTime = (endTime.getTime() - startTime.getTime()) / 1000
      let seconds = parseInt(useTime % 60)
      seconds = seconds < 10 ? '0' + seconds : seconds
      let minutes = parseInt((useTime / 60) % 60)
      minutes = minutes < 10 ? '0' + minutes : minutes
      let hours = parseInt((useTime / 3600) % 60)
      hours = hours < 10 ? '0' + hours : hours
      return `${hours}:${minutes}:${seconds}`
    }
  },
  components: {
    AuditDialog,
    Position,
    FileItem,
    FileItemTr,
    CodeEdit,
    CompareFile,
    VersionList,
    ProgressDialog,
    ProgressResultDialog,
    CodeMerge
  }
}
</script>

<style scoped lang="stylus">
.right-all{
  .file-head{
    padding 0 20px
    height 40px
    line-height 40px
    font-size 14px
    align-items center
    .icon{
      margin-left 10px
      font-size 18px
    }
  }
  .list-content{
    height calc(100% - 120px)
  }
  .list{
    padding 10px
    display flex
    flex-wrap wrap
  }
  .table-file {
    height 100%
  }
  .file-bottom{
    text-align right
    padding 0 20px
    height 39px
    line-height 39px
    border-top 1px solid #d3d3d3
    .text-underline{
      text-decoration underline
    }
  }
  // 框选样式
  .box-select{
    position absolute
    margin 0
    padding 0
    top 0
    left 0
    width 10px
    height 10px
    border 1px dashed $primary
    background-color $primary
    z-index 1000
    opacity 0.6
    display none
  }
}
</style>
<style lang="stylus">
.right-all  .table-file{
  .q-table__middle{
    height calc(100%)
  }
}
  .prompt-dialog{
    .q-dialog__message{
      position: absolute;
      bottom: 58px;
      left: -20px;
      font-size: 12px;
      color: #333
    }
  }
</style>
